#pragma once

static inline auto get_module_lua_string() -> const char* {
  static const char *module_code = R"(
    -- disable coroutine method, keep coroutine.yield
    coroutine.create = nil
    coroutine.resume = nil
    coroutine.status = nil
    coroutine.wrap = nil
    coroutine.running = nil

    function _print(...)
      local s = ""
      for i,v in ipairs({...}) do
        s = s .. tostring(v) .. " "
      end
      kratos_log(2, s)
    end

    -- redirect lua print method
    print = _print

    ctx = {}

    function kratos_sleep(ms)
      __kratos_sleep(ms)
      coroutine.yield()
    end

    function ctx:sleep(ms)
      kratos_sleep(ms)
    end

    function ctx:cancel(id)
      kratos_cancel_timer(id)
    end

    function ctx:expire_at(intval, func)
      if func == nil then
        return nil
      end
      return kratos_start_timer(intval, func)
    end

    function ctx:expire_periodic(intval, func)
      if func == nil then
        return nil
      end
      return kratos_start_periodic_timer(intval, func)
    end

    function ctx:shutdown()
      kratos_shutdown()
    end

    function ctx:register_service(name)
      return kratos_register_service(name)
    end

    function ctx:unregister_service(name)
      return kratos_unregister_service(name)
    end

    function ctx:log_verb(s)
      kratos_log(1, s)
    end

    function ctx:log_info(s)
      kratos_log(2, s)
    end

    function ctx:log_debug(s)
      kratos_log(3, s)
    end

    function ctx:log_warn(s)
      kratos_log(4, s)
    end

    function ctx:log_except(s)
      kratos_log(5, s)
    end

    function ctx:log_fail(s)
      kratos_log(6, s)
    end

    function ctx:log_fatal(s)
      kratos_log(7, s)
    end

    function ctx:remove_proxy(proxy)
      kratos_remove_proxy(proxy.proxy_id)
    end

    function ctx:get_proxy_timeout(service_name, service_uuid, timeout)
      local proxy_id = kratos_try_get_proxy(service_name, service_uuid, timeout)
      if proxy_id == nil then
          coroutine.yield()
          proxy_id = kratos_try_get_proxy(service_name, service_uuid, 0)
          if proxy_id == nil then
              return nil
          else
             local proxy_table = {}
             proxy_table.proxy_id = proxy_id
             proxy_table.service_uuid = service_uuid
             proxy_table.service_name = service_name
             return proxy_table
          end
      else
          local proxy_table = {}
          proxy_table.proxy_id = proxy_id
          proxy_table.service_uuid = service_uuid
          proxy_table.service_name = service_name
          return proxy_table
      end
    end

    function ctx:get_proxy_from_peer(arg1)
      local service_uuid, proxy_id, global_index = kratos_get_proxy_from_peer(arg1)
      if proxy_id == nil then
        return nil
      end
      local proxy_table = {}
      proxy_table.proxy_id = proxy_id
      proxy_table.service_uuid = service_uuid
      proxy_table.global_index = global_index
      return proxy_table
    end

    function ctx:get_proxy_from_transport(arg1)
      local service_uuid, proxy_id = kratos_get_proxy_from_peer(arg1)
      if proxy_id == nil then
        return nil
      end
      local proxy_table = {}
      proxy_table.proxy_id = proxy_id
      proxy_table.service_uuid = service_uuid
      return proxy_table
    end

    function ctx:clone(object)
      local lookup_table = {}
        local function copy(object)
          if type(object) ~= "table" then
            return object
          elseif lookup_table[object] then
            return lookup_table[object]
          end          
          local new_table = {}
          lookup_table[object] = new_table
          for key, value in pairs(object) do
            new_table[copy(key)] = copy(value)
          end
          return setmetatable(new_table, getmetatable(object))
        end
      return copy(object)
    end

    function ctx:publish(evt_name, data)
      kratos_publish(evt_name, data)
    end 

    function print_r(t)  
        local print_r_cache={}
        local function sub_print_r(t,indent)
            if (print_r_cache[tostring(t)]) then
                print(indent.."*"..tostring(t))
            else
                print_r_cache[tostring(t)]=true
                if (type(t)=="table") then
                    for pos,val in pairs(t) do
                        if (type(val)=="table") then
                            print(indent.."["..pos.."] => "..tostring(t).." {")
                            sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
                            print(indent..string.rep(" ",string.len(pos)+6).."}")
                        elseif (type(val)=="string") then
                            print(indent.."["..pos..'] => "'..val..'"')
                        else
                            print(indent.."["..pos.."] => "..tostring(val))
                        end
                    end
                else
                    print(indent..tostring(t))
                end
            end
        end
        if (type(t)=="table") then
            print(tostring(t).." {")
            sub_print_r(t,"  ")
            print("}")
        else
            sub_print_r(t,"  ")
        end
        print()
    end

    function table_to_string(t)
        local fmt = ""
        local function sub_table_to_string(t,indent)
            local sub_fmt = ""
            if (type(t)=="table") then
                for pos,val in pairs(t) do
                    if (type(val)=="table") then
                        sub_fmt = sub_fmt..indent.."["..pos.."] => "..tostring(t).." {"
                        sub_fmt = sub_fmt..sub_table_to_string(val,indent..string.rep(" ",string.len(pos)+8))
                        sub_fmt = sub_fmt..indent..string.rep(" ",string.len(pos)+6).."}"
                    elseif (type(val)=="string") then
                        sub_fmt = sub_fmt..indent.."["..pos..'] => "'..val..'"'
                    else
                        sub_fmt = sub_fmt..indent.."["..pos.."] => "..tostring(val)
                    end
                end
            else
                sub_fmt = sub_fmt..indent..tostring(t)
            end
            return sub_fmt
        end
        if (type(t)=="table") then
            fmt = fmt..tostring(t).." {"
            fmt = fmt..sub_table_to_string(t,"  ")
            fmt = fmt.."}"
        else
            fmt = fmt..sub_table_to_string(t,"  ")
        end
        return fmt
    end
   
    local kratos_box_argument = {}

    function kratos_box_argument:get_config_file_path()
        return _argument_get_config_file_path()
    end

    function kratos_box_argument:get_config_file_name()
        return _argument_get_config_file_name()
    end

    function kratos_box_argument:get_max_frame()
        return _argument_get_max_frame()
    end

    function kratos_box_argument:is_daemon()
        return _argument_is_daemon()
    end

    function kratos_box_argument:get_config_center_api_url()
        return _argument_get_config_center_api_url()
    end

    function kratos_box_argument:is_open_system_exception()
        return _argument_is_open_system_exception()
    end

    ctx.argument = kratos_box_argument

    local kratos_box_config = {}
    
    function kratos_box_config:get_listener_list()
        return _config_get_listener_list()
    end

    function kratos_box_config:get_service_finder_type()
        return _config_get_service_finder_type()
    end

    function kratos_box_config:get_service_finder_hosts()
        return _config_get_service_finder_hosts()
    end

    function kratos_box_config:get_service_finder_connect_timeout()
        return _config_get_service_finder_connect_timeout()
    end

    function kratos_box_config:get_necessary_service()
        return _config_get_necessary_service()
    end

    function kratos_box_config:get_connect_other_box_timeout()
        return _config_get_connect_other_box_timeout()
    end

    function kratos_box_config:get_box_channel_recv_buffer_len()
        return _config_get_box_channel_recv_buffer_len()
    end

    function kratos_box_config:get_box_name()
        return _config_get_box_name()
    end

    function kratos_box_config:get_logger_config_line()
        return _config_get_logger_config_line()
    end

    function kratos_box_config:get_service_dir()
        return _config_get_service_dir()
    end

    function kratos_box_config:get_preload_service()
        return _config_get_preload_service()
    end

    function kratos_box_config:is_open_coroutine()
        return _config_is_open_coroutine()
    end

    function kratos_box_config:get_remote_service_repo_version_api()
        return _config_get_remote_service_repo_version_api()
    end

    function kratos_box_config:get_remote_service_repo_dir()
        return _config_get_remote_service_repo_dir()
    end

    function kratos_box_config:get_remote_service_repo_latest_version_api()
        return _config_get_remote_service_repo_latest_version_api()
    end

    function kratos_box_config:is_open_remote_update()
        return _config_is_open_remote_update()
    end

    function kratos_box_config:get_remote_repo_check_interval()
        return _config_get_remote_repo_check_interval()
    end

    function kratos_box_config:is_start_as_daemon()
        return _config_is_start_as_daemon()
    end

    function kratos_box_config:get_http_max_call_timeout()
        return _config_get_http_max_call_timeout()
    end

    function kratos_box_config:is_open_rpc_stat()
        return _config_is_open_rpc_stat()
    end

    function kratos_box_config:has_attribute(s)
        return _config_has_attribute(s)
    end

    function kratos_box_config:get_array(s)
        return _config_get_array(s)
    end 

    function kratos_box_config:get_table(s)
        return _config_get_table(s)
    end

    function kratos_box_config:get_string(s)
        return _config_get_string(s)
    end

    function kratos_box_config:get_number(s)
        return _config_get_number(s)
    end

    function kratos_box_config:get_integer(s)
        return _config_get_integer(s)
    end

    function kratos_box_config:add_reload_listener(name, func)
        return _config_add_reload_listener(name, func)
    end

    function kratos_box_config:remove_reload_listener(name)
        return _config_remove_reload_listener(name)
    end

    ctx.config = kratos_box_config

    local kratos_box_redis = {}

    function kratos_box_redis:add_host(name, host, port, user, passwd)
        return _redis_add_host(name, host, port, user, passwd)
    end

    function _do_redis_command_by_type(name, command, timeout, result_type)
        local success = _redis_do_command(name, command, timeout, result_type)
        if not success then
            return nil
        end
        return coroutine.yield()
    end

    function kratos_box_redis:string_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 1)
    end

    function kratos_box_redis:array_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 2)
    end

    function kratos_box_redis:table_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 3)
    end

    function kratos_box_redis:integer_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 4)
    end

    function kratos_box_redis:bool_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 5)
    end

    function kratos_box_redis:number_result(name, command, timeout)
       return _do_redis_command_by_type(name, command, timeout, 6)
    end

    function kratos_box_redis:start()
       return _redis_start()
    end

    function kratos_box_redis:stop()
       return _redis_stop()
    end

    ctx.redis = kratos_box_redis

    local kratos_box_time = {}

    function kratos_box_time:get_millionsecond()
       return kratos_get_millionsecond()
    end

    function kratos_box_time:get_second()
       return kratos_get_second()
    end

    function kratos_box_time:utc_diff_second()
       return kratos_utc_diff_second()
    end

    function kratos_box_time:diff_days_now(now)
       return kratos_diff_days_now(now)
    end

    function kratos_box_time:diff_days(t1, t2)
       return kratos_diff_days(t1, t2)
    end

    function kratos_box_time:get_date()
       return kratos_get_date()
    end

    function kratos_box_time:date_from_string(s)
       return kratos_date_from_string(s)
    end

    function kratos_box_time:data_from_time(t)
       return kratos_data_from_time(t)
    end

    function kratos_box_time:is_same_day(t1, t2)
       return kratos_is_same_day(t1, t2)
    end

    function kratos_box_time:is_same_week(t1, t2)
       return kratos_is_same_week(t1, t2)
    end

    function kratos_box_time:is_same_month(t1, t2)
       return kratos_is_same_month(t1, t2)
    end

    ctx.time = kratos_box_time

    local kratos_box_http = {}

    function kratos_box_http:wait_response(host, port, uri, method, header, content, timeout, cb)
       return kratos_wait_response(host, port, uri, method, header, content, timeout, cb)
    end

    function kratos_box_http:wait_request(host, port, cb)
       return kratos_wait_request(host, port, cb)
    end

    ctx.http = kratos_box_http

    local kratos_box_console = {}
    
    function kratos_box_console:add_switch(name, tips, refresh_cb, change_cb)
       return kratos_add_switch(name, tips, refresh_cb, change_cb)
    end

    function kratos_box_console:add_selection(name, tips, refresh_cb, change_cb)
       return kratos_add_selection(name, tips, refresh_cb, change_cb)
    end

    ctx.console = kratos_box_console
  )";
  return module_code;
}
